/*
* @desc:腾讯云短信发送
* @company:云南奇讯科技有限公司
* @Author: yixiaohu
* @Date:   2022/1/13 11:39
 */

package service

import (
	"context"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/text/gregex"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111"
	"github.com/tiger1103/gfast/v3/internal/app/plugins/sms/dao"
	"github.com/tiger1103/gfast/v3/internal/app/plugins/sms/driver"
	"github.com/tiger1103/gfast/v3/internal/app/plugins/sms/model"
)

var Ten = new(tenService)

type tenConfig struct {
	AppKey     string
	AppSecret  string
	Host       string
	Region     string
	SdkAppId   g.Map
	TemplateId g.Map
	SignName   g.Map
}

type tenService struct {
	TenConfig *tenConfig
}

func (s *tenService) SendTemplateSms(args *driver.SendSmsArgs) (err error) {
	err = s.setConfig(args.Ctx)
	if err != nil {
		return
	}
	if len(args.Mobiles) < 1 {
		err = gerror.New("手机号码不能为空")
		return
	}
	var templateId string
	if v, ok := s.TenConfig.TemplateId["notice"]; ok {
		templateId = gconv.String(v)
	}
	if args.TemplateId != "" {
		templateId = args.TemplateId
	}
	for i, mobile := range args.Mobiles {
		// 清除手机号中的空格和横杆
		args.Mobiles[i], err = gregex.ReplaceString("\\s|-", "", mobile)
		if err != nil {
			return
		}
	}
	credential := common.NewCredential(
		s.TenConfig.AppKey,
		s.TenConfig.AppSecret,
	)
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = s.TenConfig.Host
	client, _ := sms.NewClient(credential, s.TenConfig.Region, cpf)
	request := sms.NewSendSmsRequest()
	// 必填参数
	request.PhoneNumberSet = common.StringPtrs(args.Mobiles)
	request.SmsSdkAppId = common.StringPtr(gconv.String(s.TenConfig.SdkAppId["notice"]))
	request.TemplateId = common.StringPtr(templateId)
	if v, ok := s.TenConfig.SignName["notice"]; ok {
		request.SignName = common.StringPtr(gconv.String(v))
	}
	if len(args.Params) > 0 {
		request.TemplateParamSet = common.StringPtrs(args.Params)
	}
	response, err := client.SendSms(request)
	//g.Log().Printf("%s\n", response.ToJsonString())
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		g.Log().Printf(args.Ctx,"An API error has returned: %s\n", err)
		return
	}
	//写入发送日志
	err = Sms.WriteLog(args.Ctx,&model.ClientArg{
		SmsType:    "ten",
		MsgType:    "SendTemplateSms",
		Result:     gconv.String(response),
		TemplateId: gconv.String(s.TenConfig.TemplateId["notice"]),
		Mobiles:    args.Mobiles,
		Params:     args.Params,
	})
	return
}

func (s *tenService) SendVerifyCode(args *driver.SendSmsArgs) (err error) {
	err = s.setConfig(args.Ctx)
	if err != nil {
		return
	}
	if len(args.Mobiles) < 1 {
		err = gerror.New("手机号码不能为空")
		return
	}
	mobile, _ := gregex.ReplaceString("\\s|-", "", args.Mobiles[0])
	authCode, err := Sms.CreateVerifyCode(args.Ctx,mobile)
	if err != nil {
		return
	}
	credential := common.NewCredential(
		s.TenConfig.AppKey,
		s.TenConfig.AppSecret,
	)
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = s.TenConfig.Host
	client, _ := sms.NewClient(credential, s.TenConfig.Region, cpf)
	request := sms.NewSendSmsRequest()
	// 必填参数
	request.PhoneNumberSet = common.StringPtrs([]string{mobile})
	request.SmsSdkAppId = common.StringPtr(gconv.String(s.TenConfig.SdkAppId["verifyCode"]))
	request.TemplateId = common.StringPtr(gconv.String(s.TenConfig.TemplateId["verifyCode"]))
	request.TemplateParamSet = common.StringPtrs([]string{gconv.String(authCode)})
	if v, ok := s.TenConfig.SignName["verifyCode"]; ok {
		request.SignName = common.StringPtr(gconv.String(v))
	}
	response, err := client.SendSms(request)
	//g.Log().Printf("%s\n", response.ToJsonString())
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		g.Log().Printf(args.Ctx,"An API error has returned: %s\n", err)
		return
	}
	//写入发送日志
	err = Sms.WriteLog(args.Ctx,&model.ClientArg{
		SmsType:    "ten",
		MsgType:    "SendVerifyCode",
		Result:     gconv.String(response),
		TemplateId: gconv.String(s.TenConfig.TemplateId["verifyCode"]),
		Mobiles:    args.Mobiles,
		Params:     []string{gconv.String(authCode)},
	})
	return
}

func (s *tenService) CheckVerifyCode(ctx context.Context,mobile string, code string) (err error) {
	// 本地服务器check
	return Sms.CheckVerifyCode(ctx,mobile, code)
}

// 设置配置
func (s *tenService) setConfig(ctx context.Context) (err error) {
	if s.TenConfig == nil {
		s.TenConfig, err = s.GetConfig(ctx)
	}
	return
}

func (s *tenService) GetConfig(ctx context.Context) (config *tenConfig, err error) {
	smsConfig, err := dao.PluginSmsConfig.Ctx(nil).Where("sms_type", "ten").One()
	if err != nil {
		g.Log().Error(ctx,err)
		return
	}
	if smsConfig.IsEmpty() {
		err = gerror.New("短信配置信息不存在")
		g.Log().Error(ctx,err)
		return
	}

	if v, ok := smsConfig["config"]; ok {
		err = gconv.Struct(v, &config)
		if err != nil {
			g.Log().Error(ctx,err)
			return
		}
	}
	if config.AppKey == "" || config.AppSecret == "" {
		err = gerror.New("腾讯云短信配置有错误")
		g.Log().Error(ctx,err)
		return
	}
	return
}
